package org.bees.cms.web.util.velocity;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.servlet.ServletContext;

import org.apache.velocity.app.Velocity;
import org.bees.cms.common.Enumerable;
import org.bees.cms.core.clause.Calculation.Gamma;
import org.bees.cms.core.clause.Criterion.Connector;
import org.bees.cms.core.clause.Criterion.Rule.Operator;
import org.bees.cms.core.clause.Criterion.Rule.Type;
import org.bees.cms.core.style.Scope;
import org.bees.cms.core.util.Gender;

public class Configuration {
	static Properties properties;
	static Map<String, Class<?>> renderers;
	static Map<String, Class<?>> editers;
	static Map<String, Object> globals;
	static Map<String, Class<?>> tables;
	static Map<String, Class<? extends Enum<? extends Enumerable>>> enumerations;

	public static void initialize(ServletContext context) {
		{
			try {
				properties = read("/velocity/velocity.properties");
				String logRealPath = context.getRealPath(properties.getProperty("runtime.log"));
				String templateRealPath = context.getRealPath(properties.getProperty("file.resource.loader.path"));
				properties.setProperty("runtime.log", logRealPath);
				properties.setProperty("file.resource.loader.path", templateRealPath);
				Velocity.init(properties);
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
		}

		{
			try {
				renderers = new HashMap<String, Class<?>>();
				Properties properties = read("/velocity/velocity-renderer.properties");
				for (Map.Entry<Object, Object> entry : properties.entrySet()) {
					String key = (String) entry.getKey();
					Class<?> clazz = Class.forName((String) entry.getValue());
					renderers.put(key, clazz);
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
		}

		{
			try {
				editers = new HashMap<String, Class<?>>();
				Properties properties = read("/velocity/velocity-editer.properties");
				for (Map.Entry<Object, Object> entry : properties.entrySet()) {
					String key = (String) entry.getKey();
					Class<?> clazz = Class.forName((String) entry.getValue());
					editers.put(key, clazz);
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
		}

		{
			try {
				globals = new HashMap<String, Object>();
				Properties properties = read("/velocity/velocity-global.properties");
				for (Map.Entry<Object, Object> entry : properties.entrySet()) {
					String key = (String) entry.getKey();
					Object attribute = Class.forName((String) entry.getValue()).newInstance();
					globals.put(key, attribute);
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
		}

		{
			try {
				tables = new HashMap<String, Class<?>>();
				Properties properties = read("/velocity/velocity-table.properties");
				for (Map.Entry<Object, Object> entry : properties.entrySet()) {
					String key = (String) entry.getKey();
					Class<?> clazz = Class.forName((String) entry.getValue());
					tables.put(key, clazz);
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
		}

		{
			enumerations = new HashMap<String, Class<? extends Enum<? extends Enumerable>>>();
			enumerations.put("gamma", Gamma.class);
			enumerations.put("operator", Operator.class);
			enumerations.put("connector", Connector.class);
			enumerations.put("type", Type.class);
			enumerations.put("gender", Gender.class);
			enumerations.put("scope", Scope.class);
		}
	}

	public static void destroy() {
		properties.clear();
		renderers.clear();
		editers.clear();
		globals.clear();
	}

	public static String getProperty(String key) {
		return properties.getProperty(key);
	}

	public static Class<?> getRenderer(String key) {
		return renderers.get(key);
	}

	public static Class<?> getEditer(String key) {
		return editers.get(key);
	}

	public static Object getGlobal(String key) {
		return globals.get(key);
	}

	public static Class<?> getTable(String key) {
		return tables.get(key);
	}

	public static Class<? extends Enum<? extends Enumerable>> getEnumeration(String key) {
		return enumerations.get(key);
	}

	private static Properties read(String path) {
		Properties properties = new Properties();
		InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
		properties = new Properties();
		try {
			properties.load(stream);
			return properties;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (stream != null) {
				try {
					stream.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return null;
	}

}
